package pl.elka.simulator;

import pl.elka.simulator.core.Position;
import pl.elka.simulator.core.Segment;
import pl.elka.simulator.core.configurationCommand.ConfigurationCommandFactory;
import pl.elka.simulator.core.configurationCommand.impl.AddAreaConstraintConfigurationCommand;
import pl.elka.simulator.core.configurationCommand.impl.AddConstraintConfigurationCommand;
import pl.elka.simulator.core.configurationCommand.impl.AddGravityAttractionPointConfigurationCommand;
import pl.elka.simulator.core.configurationCommand.impl.AddLeaderConfigurationCommand;
import pl.elka.simulator.core.configurationCommand.impl.AddNodeConfigurationCommand;
import pl.elka.simulator.core.configurationCommand.impl.AddTreasureConfigurationCommand;
import pl.elka.simulator.core.configurationCommand.impl.DeleteConstraintConfigurationCommand;
import pl.elka.simulator.core.configurationCommand.impl.DeleteGravityAttractionPointConfigurationCommand;
import pl.elka.simulator.core.configurationCommand.impl.DeleteLeaderConfigurationCommand;
import pl.elka.simulator.core.configurationCommand.impl.DeleteNodeConfigurationCommand;
import pl.elka.simulator.core.configurationCommand.impl.DeleteTreasureConfigurationCommand;
import pl.elka.simulator.core.configurationCommand.impl.param.PositionChainParamConstructor;
import pl.elka.simulator.core.configurationCommand.impl.param.PositionParamConstructor;
import pl.elka.simulator.core.mobilityManager.MobilityManagerFactory;
import pl.elka.simulator.core.mobilityManager.impl.ExplorerMobilityManager;
import pl.elka.simulator.core.mobilityManager.impl.FlockMobilityModel;
import pl.elka.simulator.core.mobilityManager.impl.GravityMobilityManager;
import pl.elka.simulator.core.mobilityManager.impl.RandomWalkMobilityManager;
import pl.elka.simulator.core.mobilityManager.impl.RealisticRandomDirectionMobilityManager;
import pl.elka.simulator.core.mobilityManager.impl.ReferencePointGroupMobilityManager;
import pl.elka.simulator.gui.swt.SWTMain;

public class Main {	

	    public static void main(String[] args) {
	    	
	    	MobilityManagerFactory.getInstance().registerPattern(new RandomWalkMobilityManager());
	    	MobilityManagerFactory.getInstance().registerPattern(new RealisticRandomDirectionMobilityManager());
	    	MobilityManagerFactory.getInstance().registerPattern(new GravityMobilityManager());
	    	MobilityManagerFactory.getInstance().registerPattern(new ReferencePointGroupMobilityManager());
	    	MobilityManagerFactory.getInstance().registerPattern(new FlockMobilityModel());
	    	MobilityManagerFactory.getInstance().registerPattern(new ExplorerMobilityManager());
	    	
	    	
	    	ConfigurationCommandFactory.getInstance().registerCommandPattern(new AddNodeConfigurationCommand(), new PositionParamConstructor());
	    	ConfigurationCommandFactory.getInstance().registerCommandPattern(new DeleteNodeConfigurationCommand(), new PositionParamConstructor());
	    	ConfigurationCommandFactory.getInstance().registerCommandPattern(new AddConstraintConfigurationCommand(), new PositionChainParamConstructor());
	    	ConfigurationCommandFactory.getInstance().registerCommandPattern(new DeleteConstraintConfigurationCommand(), new PositionParamConstructor());	    	
	    	ConfigurationCommandFactory.getInstance().registerCommandPattern(new AddTreasureConfigurationCommand(), new PositionParamConstructor());	    	
	    	ConfigurationCommandFactory.getInstance().registerCommandPattern(new DeleteTreasureConfigurationCommand(), new PositionParamConstructor());
	    	ConfigurationCommandFactory.getInstance().registerCommandPattern(new AddGravityAttractionPointConfigurationCommand(), new PositionParamConstructor());
	    	ConfigurationCommandFactory.getInstance().registerCommandPattern(new DeleteGravityAttractionPointConfigurationCommand(), new PositionParamConstructor());
	    	ConfigurationCommandFactory.getInstance().registerCommandPattern(new AddAreaConstraintConfigurationCommand(), new PositionChainParamConstructor());
	    	ConfigurationCommandFactory.getInstance().registerCommandPattern(new AddLeaderConfigurationCommand(), new PositionParamConstructor());
	    	ConfigurationCommandFactory.getInstance().registerCommandPattern(new DeleteLeaderConfigurationCommand(), new PositionParamConstructor());
	    	
//	    	System.out.println(findCollision(new Position(-0.1325507f,0.00899002f), new Position(-0.12935805f,0.0047286083f),
//	    			new Segment(new Position(-0.27540982f,0.15405405f), new Position(0.209836f,0.048648655f))));
	    	
	        SWTMain.run();
	    }	
	    private static float det(Position p1, Position p2, Position p3) {
			return p1.x*p2.y + p2.x*p3.y + p3.x*p1.y - p3.x*p2.y - p1.x*p3.y - p2.x*p1.y;
		}
	    private static Position crosscut(Position l1p1,Position l1p2, Position l2p1, Position l2p2){			
	    	if(l1p1.x == l1p2.x){
	    		float x = l1p2.x;
	    		float a2 = (l2p1.y - l2p2.y)/(l2p1.x - l2p2.x);	
	    		float b2 = l2p1.y - a2*l2p1.x;
	    		float y = a2*x+b2;
	    		return new Position(x,y);
	    	}
	    	if(l2p1.x == l2p2.x){
	    		float x = l2p2.x;
	    		float a1 = (l1p1.y - l1p2.y)/(l1p1.x - l1p2.x);	
	    		float b1 = l1p1.y - a1*l1p1.x;
	    		float y = a1*x+b1;
	    		return new Position(x,y);
	    	}
	    	
			float a1 = (l1p1.y - l1p2.y)/(l1p1.x - l1p2.x);
			float a2 = (l2p1.y - l2p2.y)/(l2p1.x - l2p2.x);
						
			
			float b1 = l1p1.y - a1*l1p1.x;
			float b2 = l2p1.y - a2*l2p1.x;
			
			float w = a2 - a1;
			float wx = b1 - b2;
			float wy = a2*b1 - a1*b2;
			
			return new Position(wx/w,wy/w);
		}
	    private static boolean onSegment(Position p1, Position p2, Position p3) {
			return
					Math.min(p1.x, p2.x)<=p3.x 
					&& p3.x <= Math.max(p1.x, p2.x)
					&& Math.min(p1.y, p2.y)<=p3.y
					&& p3.y<=Math.max(p1.y, p2.y);
		}
	    private static Position findCollision(Position e1, Position e2, Segment edge) {
			float d1 = det(e1,e2,edge.begin);
			float d2 = det(e1,e2,edge.end);
			float d3 = det(edge.begin,edge.end,e1);
			float d4 = det(edge.begin,edge.end,e2);
			
			if(d1*d2<0 && d3*d4<0){
				return crosscut(e1,e2, edge.begin,edge.end);
			}
			if(d1==0 && onSegment(e1,e2,edge.begin)){
				return crosscut(e1,e2, edge.begin,edge.end);
			}
			if(d2==0 && onSegment(e1,e2,edge.end)){
				return crosscut(e1,e2, edge.begin,edge.end);
			}
			if(d3==0 && onSegment(edge.begin,edge.end,e1)){
				return crosscut(e1,e2, edge.begin,edge.end);
			}
			if(d4==0 && onSegment(edge.begin,edge.end,e2)){
				return crosscut(e1,e2, edge.begin,edge.end);
			}
			
			return null;
		}
}
